%> @file ccd_photosensor.m
%> @brief This routine simulates the behaviour of a CCD/CMOS sensor, performing the conversion from irradiance to electrons, then volts, and then digital numbers.
%> @author Mikhail V. Konnik
%> @date   17 January 2011, reworked on 4 December 2014.
%> 
%> @section ccdphotosensor High-level photosensor model
%> The process from incident photons to the digital numbers appeared on the image is outlined. 
%> First of all, the radiometry is considered. Then, the process of conversion from photons to electrons is outlined. 
%> Following that, conversion from electrons to voltage is described. 
%> Finally, the ADC converts the voltage signal into digital numbers. The whole process is depicted on Figure below.
%> 
%> @image html camerascheme_horiz.png
%> 
%> Many noise sources contribute to the resulting noise image that is produced by
%> photosensors. Noise sources can be broadly classified as either
%> @b fixed-pattern (time-invariant) or @b temporal (time-variant)
%> noise. Fixed-pattern noise refers to any spatial pattern that does not change
%> significantly from frame to frame. Temporal noise, on the other hand, changes
%> from one frame to the next. These noise sources will be described in detail in
%> the following parts of the simulator:
%> 
%>  - @ref secphoton2electron "From Photon to Charge:" light noises
%>    - @ref photonshotnoisesimulation "Photon Shot noise simulation", starting from @ccd.Signal_CCD_photons matrix
%>    - Converting the signal from Photons to Electrons, getting @b ccd.light_signal matrix
%>    - @ref prnusim "Simulation of photo response non-uniformity (PRNU)"
%>    - Dark noises simulation:
%>       - @ref readnoise "Dark signal generation", getting @b ccd.dark_signal matrix
%>       - @ref darkshotnoisesim "Dark Shot Noise"
%>       - @ref darkfpnsimulaiton "Simulation of dark current Fixed Pattern Noise"
%>       - @ref sourcefollownoise "Source Follower Noise"
%>  - From Charge to Voltage: 
%>    - obtaining @b ccd.Signal_CCD_electrons matrix by adding @b ccd.light_signal and @b ccd.dark_signal
%>    - @ref sensenode "Sense Node": Converting charge to voltage
%>    - @ref sensenoderesetnoise "Sense node Reset noise" (kTC noise)
%>    - obtaining @b ccd.Signal_CCD_voltage matrix 
%>  - From Voltage to Digital Numbers: 
%>    - @ref sourcefollowerdescr "Source Follower"
%>    - @ref cds "Correlated Double Sampling"
%>    - @ref adcdescribe "Analogue to Digital converter" (ADC)
%>  - The final result is in the @b ccd.Signal_CCD_DN matrix, in digital numbers.
%> 
%> The order of noise can be altered if needed, the noise sources can be turned off/on.
%======================================================================
%> @param Uin		= light field incident on the photosensor [matrix NxM], [Watt/m2].
%> @param ccd		= structure that contains parameters of the sensor (exposure time and so on).
%>
%> @retval ccd 		= structure with new field @b Signal_CCD_electrons signal of the photosensor in electrons [matrix NxM], [e].
% ======================================================================
function ccd = ccd_photosensor(Uin,ccd);


if ( isfield(ccd,'SensorType') == 0 )
    error('Sensor Simulator::: please choose (uncomment) at least one type of sensor, CMOS or CCD!')
end

ccd = ccd_set_photosensor_constants(ccd,Uin); %%% defining the constants such as speed of light c, Plank's h, and others.


%%%%% <----- ### Start:: adding light noises
if (ccd.flag.darkframe ~= 1) %%%%%%%%#### Section: if this is NOT a complete darkness
    ccd = ccd_photosensor_lightnoises(ccd, Uin); 
end 
%%%%% <----- ### END:: adding light noises


%%%%% <----- ### Start:: adding dark current noise
if (ccd.flag.darkcurrent == 1)
     ccd = ccd_photosensor_darknoises(ccd);
end
%%%%% <----- ### END:: adding dark current noise


%%%%% <----- ### Start:: adding dark current and light electrons 
ccd.Signal_CCD_electrons = ccd.light_signal + ccd.dark_signal; %%% adding the electrones generated by dark signal and electrones generated by light.

% figure, imagesc(ccd.light_signal);
% figure, imagesc(ccd.dark_signal);

    %%%%%%%%%%%######### Full-well check-up (if there more electrons than depth of the pixel - saturate the pixel)
        idx = (ccd.Signal_CCD_electrons>=ccd.FW_e); %%% find all of pixels that are saturated (there are more electrons that full-well of the pixel)
        ccd.Signal_CCD_electrons(idx) = ccd.FW_e;  %% saturate the pixel if there are more electrons than full-well.

        idx = (ccd.Signal_CCD_electrons<0); %%% find all of pixels that are less than zero
        ccd.Signal_CCD_electrons(idx) = 0; %%% truncate pixels that are less than zero to zero. (there no negative electrons).
    %%%%%%%%%%%######### END Full-well check-up

ccd.Signal_CCD_electrons = floor(ccd.Signal_CCD_electrons);  %% round the number of electrons.        
%%%%% <----- ### END:: adding dark current and light electrons     


%%%%% <----- ### Start:: Sense Node - charge-to-voltage conversion
ccd = ccd_sense_node_chargetovoltage(ccd); %%% Charge-to-Voltage conversion by Sense Node
%%%%% <----- ### END:: Sense Node - charge-to-voltage conversion


%%%%% <----- ### Start:: Source Follower - Voltages
ccd = ccd_source_follower(ccd); %%% Signal's Voltage amplification by Source Follower
%%%%% <----- ### END:: Source Follower - Voltages


%%%%% <----- ### Start:: Correlated Double Sampling
ccd = ccd_cds(ccd); %%% Signal's amplification and de-noising by Correlated Double Sampling
%%%%% <----- ### END:: Correlated Double Sampling


%%%%% <----- ### Start:: Analogue-To-Digital Converter
ccd = ccd_adc(ccd); %% Quantization ADC
%%%%% <----- ### END:: Analogue-To-Digital Converter